/***************************************************************************
													expr.h  -  description
														 -------------------
		begin                : Fri Jun 21 2002
		copyright            : (C) 2002 by Michiel Visser
		email                : 
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
 
#ifndef EXPR_H
#define EXPR_H

#include "context.h"
#include <vector>

using namespace Obj;
using namespace Sess;
using namespace std;

namespace Expression
{

#define P(x,l,...) static const int level##x=l;
	#include"parseunits.h"
#undef P

#define PREPENDA_A(op,array) { array.prepend(op); }
#define PREPENDSTR_A(string,array) PREPENDA_A(NEW_OBJ StringObject(string),array)

#define ADDA(op) _MACRO_BEGIN array->prepend(op); array++; _MACRO_END
#define ADDSTR(string) ADDA(NEW_OBJ StringObject(string))

inline Object *CodeComponent::evaluateToCopy() { Object *o=ao(); objectGC.paintPermanent(o,1); evaluateToCopy(o); objectGC.paintPermanent(o,0); return o; } 
inline void CodeComponent::evaluateToPersistCopy(void *space) { evaluateToCopy(space); ((Object *)space)->persist(); }
inline Object *CodeComponent::evaluateToPersistCopy() { Object *o=evaluateToCopy(); o->persist(); return o; } 


#define FUNC_COPY void evaluateToCopy(void *space);
#define FUNC_ORIGINAL Object *evaluateToOriginal();
#define FUNC_VOID void evaluateToVoid();

struct ConstExpr: public Expr
{
	Object::Holder m_val;
	ConstExpr(Object *val) { val->duplicateIn(m_val); m_val->GCPaintMyChildrenPerm(1); }
	ConstExpr() {}
	~ConstExpr() { m_val->GCPaintMyChildrenPerm(0);}
	FUNC_COPY
	void toArgumentsArray(OList::P &array) const;
	Object *evaluateLiteralToCopy();
	IFDEBUG(void printTyle() const; )
	bool isDynamic() const;
	void toArray(OList::P array) const;
	int levelLeft() const;
};

struct SharedLiteralsScopeExpr: public Expr
{
	EPtr m_child;
	SharedLiteralsScopeExpr(EPtr c, vector<EPtr> &sos);
	vector<EPtr> m_sharedLiterals;
	//MapObject m_sharedLiterals; //todo: go back to vector in the future, because it is more efficient
	FUNC_COPY
	void toArray(OList::P array) const;
	IFDEBUG(void printTyle() const; )
protected:
	void init();
	void finish();
};

struct SharedLiteralExpr: public Expr
{
	int m_index;
	SharedLiteralExpr(int index): m_index(index) {}
	Object *evaluateLiteralToCopy();
	void toArray(OList::P array) const;
	IFDEBUG(void printTyle() const; )
	bool consolidateSharedLiterals(vector<EPtr> &sharedLiterals, bool inARef);
};

struct SharedLiteralExprAssigned: public SharedLiteralExpr
{
	EPtr m_value;
	SharedLiteralExprAssigned(int index, EPtr value=EPtr()): SharedLiteralExpr(index), m_value(value) {}
	void toArray(OList::P array) const;
	IFDEBUG(void printTyle() const; )
	bool consolidateSharedLiterals(vector<EPtr> &sharedLiterals, bool inARef);
};

struct FuncExpr: public Expr
{
	void toExprArray(OList::P array) const;
};

#define FUNC_EXPR(x) \
struct x##Expr: public FuncExpr\
{\
	x##Expr(): FuncExpr() {}\
	IFDEBUG(void printTyle() const; )\
	void toArray(OList::P array) const { ADDSTR(#x); } \
	FUNC_COPY\
};
#include "funcs.h"
#undef FUNC_EXPR

struct UniExprClass: public Expr
{
	EPtr a;
	UniExprClass(EPtr o):a(o) {}
	void iterate(void (*callback)(EPtr &e, void *param), void *param);
	virtual int token() const = 0;
	virtual String tokenString() const;
	IFDEBUG(void printTyle() const;)
	void toArray(OList::P array) const;
};

template<unsigned int Token, int Level=levelTop> struct UniExpr: public UniExprClass
{
	UniExpr(EPtr o):UniExprClass(o) {}
	int levelRight() const { return Level; }
	int token() const { return Token; }
};

/*template<unsigned int Token, int Level=levelTop> struct UniExprSmall: public UniExpr<Token, Level>
{
	UniExprSmall(EPtr o): UniExpr(o) {}
};*/

#define MC1(a) ((unsigned int)a)
#define MC2(a,b) (((unsigned int)a)|(b<<8))
#define MC3(a,b,c) (((unsigned int)a)|(b<<8)|(c<<16))
#define MC4(a,b,c,d) (((unsigned int)a)|(b<<8)|(c<<16)|(d<<24))

class BinaryExprClass: public UniExprClass
{
protected:
	EPtr b;
public:
	BinaryExprClass(EPtr na, EPtr nb): UniExprClass(na), b(nb) {}
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	void iterate(void (*callback)(EPtr &e, void *param), void *param);
	virtual int isRight() const = 0;
};

template<unsigned int Token, int Level, int Right=0> class BinaryExpr: public BinaryExprClass
{
public:
	BinaryExpr(EPtr na, EPtr nb):BinaryExprClass(na,nb) {}
	int levelLeft() const { return Level; }
	int levelRight() const { return Level; }
	int token() const { return Token; }
	int isRight() const { return Right; }
};

#define DEF_T(name,token,level,type,funcs)\
struct name##Expr: public UniExpr##type<token, level>\
{\
	name##Expr(EPtr o): UniExpr##type(o) {}\
	funcs \
};
	
#define DEF_BINEXPR_WITHOUT_CONSTRUCTOR(name,funcs,...) \
struct name##Expr: public BinaryExpr<__VA_ARGS__> { \
funcs
	
#define DEF_BINEXPR(name,funcs,...) \
DEF_BINEXPR_WITHOUT_CONSTRUCTOR(name,funcs,__VA_ARGS__) name##Expr(EPtr na, EPtr nb): BinaryExpr(na,nb) {}

#define DEF_E(name,Token,Funcs,AssignFuncs) \
DEF_BINEXPR(name,Funcs,Token, level##name) \
}; \
DEF_BINEXPR(name##Assign,AssignFuncs,Token, levelAssign) \
	String tokenString() const { String s(BinaryExpr<Token,levelAssign>::tokenString()); s[s.length()-1]='='; return s+" "; } \
};

#define DEF_C(name,Token,Funcs) \
DEF_BINEXPR(name,Funcs,Token, level##name) \
}; \

DEF_T(Negate,      MC2('-',' '),levelTop,,FUNC_COPY)
DEF_T(Inverse,     MC2('!',' '),levelTop,,FUNC_COPY)
DEF_T(BitNot,      MC2('~',' '),levelTop,,FUNC_COPY)
DEF_T(Length,      MC2('@',' '),levelTop,,FUNC_COPY)
DEF_T(Describe,    MC3('.','?',' '),levelModify,,FUNC_COPY)
DEF_T(Type,        MC3('@','@',' '),levelTop,,FUNC_COPY)
DEF_T(Reference,   MC2('&',' '),levelTop,,FUNC_COPY 	Object *evaluateLiteralToCopy();bool isContainer(bool &inARef) const;)
DEF_T(DeReference ,MC2('*',' '),levelTop,,FUNC_ORIGINAL FUNC_COPY bool isLValue() const; )
DEF_T(Value,       MC3('*','!',' '),levelTop,,FUNC_COPY FUNC_ORIGINAL)
#undef DEF_T

DEF_E(Prepend,    MC4(' ','+','<',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(InsertAt,   MC4(' ',':','+',' '),FUNC_COPY, FUNC_VOID FUNC_COPY FUNC_ORIGINAL)
DEF_E(RemoveAt,   MC4(' ',':','-',' '),FUNC_COPY,FUNC_COPY )
DEF_E(ShiftLeft,  MC4(' ','<','<',' '),FUNC_COPY,FUNC_COPY )
DEF_E(ShiftRight, MC4(' ','>','>',' '),FUNC_COPY,FUNC_COPY )
DEF_E(BitAnd,     MC3(' ','&',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(BitOr,      MC3(' ','|',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(BitXor,     MC3(' ','^',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Mul,        MC3(' ','*',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Div,        MC3(' ','/',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Mod,        MC3(' ','%',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Add,        MC3(' ','+',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Sub,        MC3(' ','-',' '),FUNC_COPY,FUNC_COPY )
DEF_E(And,        MC4(' ','&','&',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_E(Or,         MC4(' ','|','|',' '),FUNC_COPY, FUNC_COPY FUNC_VOID)
DEF_C(FindIndex,  MC3(' ','@',' '    ),FUNC_COPY)
DEF_C(Equal,      MC4(' ','=','=',' '),FUNC_COPY)
DEF_C(Unequal,    MC4(' ','!','=',' '),FUNC_COPY)
DEF_C(Smaller,    MC3(' ','<',' '    ),FUNC_COPY)
DEF_C(SmallerEqual, MC4(' ','<','=',' '),FUNC_COPY)
DEF_C(Greater,      MC3(' ','>',' '    ),FUNC_COPY)
DEF_C(GreaterEqual, MC4(' ','>','=',' '),FUNC_COPY)

DEF_BINEXPR(Assignment,FUNC_COPY FUNC_VOID, MC3(' ','=',' '),levelAssign,1)
};

class ArgumentExpr: public Expr
{
protected:
	short m_index,m_depth;
public:
	ArgumentExpr(short index, short depth): m_index(index),m_depth(depth) {}
	FUNC_ORIGINAL
	void toArray(OList::P array) const;
	bool isLValue() const;
};

class ArgumentListExpr: public Expr
{
protected:
	short m_depth;
public:
	bool isArgumentList() const;
	ArgumentListExpr(short depth): m_depth(depth) {}
	FUNC_ORIGINAL
	void toArray(OList::P array) const;
};

class IteratorVarExpr: public Expr
{
public:
	IteratorVarExpr() {}
	FUNC_ORIGINAL
	void toArray(OList::P array) const;
	bool isLValue() const;
	IFDEBUG(void printTyle() const; )	
};

class IteratorKeyVarExpr: public Expr
{
public:
	IteratorKeyVarExpr() {}
	FUNC_ORIGINAL
	void toArray(OList::P array) const;
};

class ClosureVarExpr: public Expr
{
	int m_index;
public:
	ClosureVarExpr(int index ): m_index(index) {}
	FUNC_ORIGINAL
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

#undef SUPER
#define SUPER UniExpr<MC2('?',' '),levelModify>
class ClosuredExprExpr: public SUPER
{
	ClosureScope::Ptr	m_scope;
public:
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	ClosuredExprExpr(EPtr expr, ClosureScope::Ptr scope): SUPER(expr), m_scope(scope) {}
	FUNC_COPY
};

struct TypeSelectCarrier
{
	List<TypeFunc> m_typeFuncs;
	TypeSelectCarrier(List<TypeFunc> &funcs) { m_typeFuncs.take(funcs); }
	void assignTypeVars() const;
};
	
class NamedIteratorVarExpr: public ArgumentListExpr
{
	NamedIteratorVarsScope::Ptr m_scope;
	//IFDEBUG(void printTyle() const; )
public:
	void toArray(OList::P array) const;
	NamedIteratorVarExpr(int depth, NamedIteratorVarsScope::Ptr scope): ArgumentListExpr(depth), m_scope(scope) {}
	bool isLValue() const;
};

class NamedIteratorKeyVarExpr: public NamedIteratorVarExpr
{
	NamedIteratorVarsScope::Ptr m_scope;
public:
	void toArray(OList::P array) const;
	NamedIteratorKeyVarExpr(int depth, NamedIteratorVarsScope::Ptr scope): NamedIteratorVarExpr(depth, scope) {}
};

class ParamAssignmentExpr: public UniExpr<0,levelFunction>, public TypeSelectCarrier
{
protected:
	Scope::Ptr m_scope;
	ParamAssignmentExpr(List<TypeFunc> &funcs, Scope::Ptr scope, EPtr child):
		UniExpr<0,levelFunction>(child), TypeSelectCarrier(funcs), m_scope(scope) {}
};

class NamedIteratorVarAssignmentExpr: public ParamAssignmentExpr
{
	void initEval() const;
public:
	Ptr<TypeFunc>::Own m_func, m_keyFunc;
	FUNC_COPY
	FUNC_VOID
	NamedIteratorVarAssignmentExpr(TypeFunc *func, TypeFunc *keyFunc, List<TypeFunc> &funcs, NamedIteratorVarsScope::Ptr scope, EPtr child):
		ParamAssignmentExpr(funcs,scope,child), m_func(func), m_keyFunc(func) {}
	void toArray(OList::P array) const;
	IFDEBUG(void printTyle() const; )
};

class ParamListAssignmentExpr: public ParamAssignmentExpr
{
	void initEval() const;
public:
	FUNC_COPY
	FUNC_VOID
	void toArray(OList::P array) const;
	ParamListAssignmentExpr(List<TypeFunc> &funcs, NamedIteratorVarsScope::Ptr scope, EPtr child):
		ParamAssignmentExpr(funcs,scope, child) {}
	IFDEBUG(void printTyle() const; )
};

class ParamExpr: public ArgumentListExpr
{
	int m_depth;
	StructIndex m_index;
public:
	ParamExpr(String name, int depth): ArgumentListExpr(depth),m_index(name) {}
	FUNC_ORIGINAL
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	bool updateIndex();
	bool isLValue() const;
};

class BlockVarExpr: public Expr
{
	LocalVarVectorQueue::Ptr queue;
	int number;
public:
	BlockVarExpr(LocalVarVectorQueue::Ptr q, int n): queue(q), number(n) {}
	FUNC_COPY
	FUNC_ORIGINAL
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

class LocalBlockVarExpr: public BlockVarExpr
{
public:
	LocalBlockVarExpr(LocalVarVectorQueue::Ptr q, int n): BlockVarExpr(q,n) {}
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

class GlobalVarInitialExpr: public Expr // compiler assert needed on: sizeof(GlobalVarExpr)==sizeof(GlobalVarInitialExpr)
{
	String m_name;
public:
	GlobalVarInitialExpr(String name): m_name(name) {}
	FUNC_ORIGINAL
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

class GlobalVarExpr: public Expr
{
	GlobalVariable &m_v;
public:
	GlobalVarExpr(GlobalVariable &v): m_v(v) {}
	FUNC_ORIGINAL
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

#undef SUPER
#define SUPER UniExpr<0,levelSwitch>
class SwitchOnExpr: public SUPER // actually, switchOn can also be statement, depending on children
{
	EList m_choices;
public:
	SwitchOnExpr(EPtr o, EList &choices): SUPER(o) { m_choices.take(choices); }
	FUNC_COPY
	//todo: FUNC_VOID
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	void iterate(void (*callback)(EPtr &e, void *param), void *param);
	bool isExpr() const;
};

DEF_BINEXPR(Catch,FUNC_VOID,MC4(' ','<','!','~'),levelProcedure) //todo: level
};

struct EListExpr: public Expr {
	EList m_elements;
	typedef EList::P P;
	EListExpr(EList &elements):Expr() { m_elements.take(elements); }	
	void iterate(void (*callback)(EPtr &e, void *param), void *param);
};

struct MapExpr: public EListExpr
{
	MapExpr(EList &elements):EListExpr(elements) { }
	FUNC_COPY
	EPtr getPredefined() const;
	void evaluateLiteralToCopy(void *space);
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	bool isContainer(bool &inARef) const;
#ifdef VIRTUAL_PERSIST_COPY
	Object *evaluateToPersistCopy();
#endif
};

struct ListExpr: public EListExpr
{
	ListExpr(EList &elements):EListExpr(elements) { }
	//  ListExpr(List<Elem> &e,VarVectorQueue &q):BlockExpr(q) { m_elements.take(e); }
	FUNC_COPY
#ifdef VIRTUAL_PERSIST_COPY
	Object *evaluateToPersistCopy();
#endif
	void toArgumentsArray(OList::P &array) const;
	EPtr getPredefined() const;
	IFDEBUG(void printTyle() const; )
	virtual void toArray(OList::P array) const;
	bool isContainer(bool &inARef) const;
	void evaluateLiteralToCopy(void *space);
};

struct SequenceExpr: public EListExpr
{
	SequenceExpr(EList &elements):EListExpr(elements) { }
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

struct MultiStat: public EListExpr
{
	int levelLeft() const;
	LocalVarVectorQueue::Ptr m_queue;
	bool isSingleResult() const;
	MultiStat(EList &elements, LocalVarVectorQueue::Ptr queue): EListExpr(elements), m_queue(queue) { }
	FUNC_COPY
	FUNC_VOID
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	bool isExpr() const;
	~MultiStat();
protected:
	void push() {	if (!!m_queue) { session.execPushLvvq(m_queue);} }
	void pop() { if (!!m_queue) session.execPopLvvq(); }
};

struct FlowChangerWithoutResultStatement: public Statement
{
	Session::FlowState m_newState;
	FlowChangerWithoutResultStatement(Session::FlowState state): m_newState(state) {}
	FUNC_VOID
	void toArray(OList::P array) const;
};

struct FlowChangerWithResultStatement: public FlowChangerWithoutResultStatement
{
	EPtr m_result;
	bool isSingleResult() const;
	FlowChangerWithResultStatement(Session::FlowState state, EPtr result): FlowChangerWithoutResultStatement(state), m_result(result) {}
	FUNC_VOID
	void toArray(OList::P array) const;
};

DEF_BINEXPR(Index,FUNC_ORIGINAL,0,levelTop)
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
	FUNC_COPY
};

DEF_BINEXPR(IndexAlt,FUNC_COPY,0,levelTop)
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

//DEF_BINEXPR(While,FUNC_COPY, ,levelSwitch)};

struct TypeSelectionExpr: public UniExpr<0,levelTop>, public TypeSelectCarrier
{ 
	Ptr<TypeFunc>::Own m_func;
	TypeSelectionExpr(TypeFunc *func, List<TypeFunc> &funcs):
	UniExpr<0,levelTop>(EPtr()), TypeSelectCarrier(funcs),m_func(func) {}
	FUNC_ORIGINAL
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

struct StructIndexingExpr: public UniExpr<0,levelTop>
{ 
	StructIndex m_index;
	StructIndexingExpr(EPtr na, String name): UniExpr(na), m_index(name) {}
	FUNC_ORIGINAL
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
protected:
	bool updateIndex();
};

struct StructNameExpr: public UniExpr<0,levelTop>
{ 
	StructNameExpr(EPtr na): UniExpr(na) {}
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

struct StructElemsExpr: public UniExpr<0,levelTop> 
{ 
	StructElemsExpr(EPtr na): UniExpr(na) {}
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

struct StructIndexingNumberExpr: public StructIndexingExpr
{
	StructIndexingNumberExpr(EPtr na, String name): StructIndexingExpr(na,name) {}
	FUNC_COPY
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

struct StructLengthExpr: public UniExpr<0,levelTop>
{
	StructLengthExpr(EPtr na): UniExpr(na) {}
	FUNC_COPY
//	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};


DEF_BINEXPR(ActOn,FUNC_COPY FUNC_VOID, MC3(' ','~',' '),levelIterators,1)};

DEF_BINEXPR(Finally,FUNC_COPY FUNC_VOID, MC4(' ','<','~','~'),levelIterators,1)};

DEF_BINEXPR_WITHOUT_CONSTRUCTOR(ActOnMulti,FUNC_COPY, MC4(' ','~',':',' '),levelIterators,1)
	bool m_subIsExpression, m_singleResult;
	ActOnMultiExpr(EPtr na, EPtr nb): BinaryExpr(na,nb), m_subIsExpression(nb->isExpr()), m_singleResult(!m_subIsExpression&&nb->isSingleResult()) {}
};
//todo: all binaryExpr subclasses must use DEF_BINEXPR

DEF_BINEXPR(ActOnColumns,FUNC_COPY, MC4(' ','~','%',' '),levelIterators,1)};

DEF_BINEXPR(Apply,FUNC_COPY FUNC_VOID, 0,levelTop)
	//bool m_isEval,m_isSquashed;
	//ApplyExpr(EPtr na, EPtr nb): BinaryExpr(na,nb), m_isEval(isEval), m_isSquashed(isSquashed) {}
	IFDEBUG(void printTyle() const; )
	void toArray(OList::P array) const;
};

DEF_BINEXPR(ActAbstract,FUNC_COPY, MC4(' ','.','?',' '),levelIterators,1)};

} // namespace

#endif // FILEXXX_H
